package org.zuel.config;

import org.springframework.context.annotation.Lazy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.zuel.entity.Perm;
import org.zuel.service.impl.CustomAuthenticationFailureHandler;
import org.zuel.service.impl.CustomAuthenticationSuccessHandler;
import org.zuel.service.impl.JwtAuthenticationTokenFilter;
import org.zuel.service.impl.PermServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

import javax.sql.DataSource;
import java.util.List;
//SpringSecurity 新版2.7+

@EnableWebSecurity // 开启WebSecurity模式
public class SecurityConfig  {

    @Autowired
    private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;

    @Autowired
    private CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
    @Autowired
    @Lazy // 延迟注入
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    /**
     * 授权
     * @return
     */

    @Autowired
    private PermServiceImpl permService;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests((authorize) -> {
                    // 允许登录页面匿名访问
                    authorize.antMatchers("/user/regist").permitAll();
                    authorize.antMatchers("/login","/").permitAll();
                    // 直接使用全局变量中的权限数据
                    //所以，就算权限表中什么都没有，也不能使得所有权限都是被允许的，反而都需要登录，不过postman没有登录概念，所以返回html文件
                    List<Perm> permissions = permService.list();
                    for (Perm permission : permissions) {
                        if (permission.getAnonStatus() == 0) {
                            authorize.antMatchers(permission.getPermUrl()).hasAuthority(permission.getName());
                        } else {//如果是匿名权限，那也至少需要登录，只不过是不检查用户权限而已
                            authorize.antMatchers(permission.getPermUrl()).authenticated();
                        }
                    }
                    // 其他通用配置
//                    authorize.anyRequest().authenticated();//则其他均需要登录型验证
                    //也就是说，权限表里写了的，都是需要登陆型验证的，那权限是否匿名有有什么用呢，不如关掉这个。
                })
                .formLogin()
                .successHandler(customAuthenticationSuccessHandler) // 自定义登录成功处理器
                .failureHandler(customAuthenticationFailureHandler) // 自定义登录失败处理器
                .and()
                .csrf().disable()//有关安全设置，自动打开避免遭受get攻击
                .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); // 添加JWT过滤器
        return http.build();
    }

    /**
     * 认证
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {//设置密码加强器
        return new BCryptPasswordEncoder(); // 使用BCrypt加密算法
    }
    @Bean//如果数据库写法不是固定型写法，就需要更改这里的查询方法
    public UserDetailsService userDetailsService() {
        JdbcUserDetailsManager userDetailsService = new JdbcUserDetailsManager(dataSource);

        // 自定义SQL查询：查询用户信息
        userDetailsService.setUsersByUsernameQuery(
                "SELECT u.id AS username, u.password, true AS enabled FROM user u WHERE u.id = ?"
        );

        // 自定义SQL查询：查询用户角色
        userDetailsService.setAuthoritiesByUsernameQuery(//原来你的参数是sql语句字符串，而不是String 变量而已
                "SELECT u.id AS username, p.name AS authority\n" +
                        "FROM perm p\n" +
                        "JOIN role_perm rp ON p.id = rp.perm_id\n" +
                        "JOIN user_role ur ON rp.role_id = ur.role_id\n" +
                        "JOIN user u ON ur.user_id = u.id\n" +
                        "WHERE u.id = ?\n" +
                        "GROUP BY p.name;"
        );
        return userDetailsService;
    }
    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService());//设置用户权限信息
        authProvider.setPasswordEncoder(passwordEncoder());//密码加密
        return authProvider;
    }
    @Autowired//注入数据库
    private DataSource dataSource;
}
